package com.tensquare.article.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.tensquare.article.client.NoticeClient;
import com.tensquare.article.dao.ArticleDao;
import com.tensquare.article.pojo.Article;
import com.tensquare.article.pojo.TbNotice;
import com.tensquare.article.service.ArticleService;
import com.tensquare.entity.Result;
import com.tensquare.util.IdWorker;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;

/**
 * 文章(Article)表服务实现类
 *
 * @author long
 * @since 2021-07-14 11:51:07
 */
@Service("articleService")
public class ArticleServiceImpl implements ArticleService {
    @Resource
    private ArticleDao articleDao;
    @Resource
    private NoticeClient noticeClient;
    @Autowired
    private IdWorker idWorker;
    @Resource
    private StringRedisTemplate strRedisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public List<Article> findAll() {
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        wrapper.eq("isdelete", "0");
        return articleDao.selectList(wrapper);
    }

    @Override
    public Article findById(String id) {
        return articleDao.selectById(id);
    }

    /**
     * 添加文章
     */
    @Override
    public void add(Article article) {
        //初始化数据
        Date date = new Date();
        String id = String.valueOf(idWorker.nextId());
        article.setId(id);
        article.setVisits(0);
        article.setThumbup(0);
        article.setComment(0);
        article.setCreatetime(date);
        article.setUpdatetime(date);
        articleDao.insert(article);

        //存储该文章作者的所有订阅者
        String authorKey = "article_author_" + article.getUserid();
        Set<String> userIds = strRedisTemplate.opsForSet().members(authorKey);
        if (null == userIds){
            return;
        }
        Result result = null;
        for (String userId : userIds) {
            TbNotice notice = new TbNotice();
            notice.setReceiverid(userId);
            notice.setOperatorid(article.getUserid());
            notice.setAction("publish");
            notice.setTargettype("article");
            notice.setTargetid(id);
            notice.setCreatetime(date);
            notice.setType("sys");
            notice.setState("0");
            result = noticeClient.save(notice);
        }
        if (result != null) {
            if (!result.isFlag()) {
                //TODO
                //记录消息保存失败的数据
                System.err.println(result.getMessage());
            } else {
                //入库成功后，发送mq消息，内容是消息通知id
                rabbitTemplate.convertAndSend("article_subscribe", article.getUserid(), id);
            }
        }
    }

    @Override
    public void update(Article article) {
        article.setUpdatetime(new Date());
        articleDao.updateById(article);
    }

    @Override
    public void delete(String id) {
        articleDao.deleteArticleById(id);
    }

    public Page<Article> search(Map<String, String> map, int size, int page) {
        QueryWrapper<Article> wrapper = new QueryWrapper<>();
        Page<Article> articlePage = new Page<>(page, size);
        Set<String> keys = map.keySet();
        for (String key : keys) {
            wrapper.eq(null != key, key, map.get(key));
        }
        wrapper.eq("isdelete", 0);
        System.out.println("--"+page + "--"+size + "--------------");
        articleDao.selectPage(articlePage, wrapper);
        return articlePage;
    }

    /**
     * 订阅作者
     */
    @Override
    public boolean subscribe(String userId, String authorId) {
//        String userId = map.get("userId");
//        String articleId = map.get("articleId");
//        String authorId = map.get("authorId");
        //根据文章id获取作者Id
//        String authorId  = articleDao.selectById(articleId).getUserid();

        String userKey = "article_subscribe_" + userId;
        String authorKey = "article_author_" + authorId;

        //创建Rabbit管理器
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate);
        //声明exchange，直连型交换机
        DirectExchange exchange = new DirectExchange("article_subscribe");
        rabbitAdmin.declareExchange(exchange);
        //创建queue
        Queue queue = new Queue("article_subscribe_" + userId, false);
        //声明exchange和queue的绑定关系，设置路由键为作者id
        /*
            大致流程，有一个队列绑定到一个直连交换机上，同时赋予一个路由键 routing key 。
            然后当一个消息携带着路由值为X，这个消息通过生产者发送给交换机时，
            交换机就会根据这个路由值X去寻找绑定值也是X的队列。
         */
        Binding binding = BindingBuilder.bind(queue).to(exchange).with(authorId);

        Boolean member = strRedisTemplate.opsForSet().isMember(userKey, authorId);
        Assert.notNull(member, "redis is null");
        if (member) {
            strRedisTemplate.opsForSet().remove(userKey, authorId);
            strRedisTemplate.opsForSet().remove(authorKey, userId);

            //删除绑定的队列
            rabbitAdmin.removeBinding(binding);
            return false;
        } else {
            //如果为flag为false，没有订阅，则进行订阅
            strRedisTemplate.opsForSet().add(userKey, authorId);
            strRedisTemplate.opsForSet().add(authorKey, userId);

            //声明队列和绑定队列
            rabbitAdmin.declareQueue(queue);
            rabbitAdmin.declareBinding(binding);
            return true;
        }
    }

    /**
     * 文章点赞
     */
    @Override
    public void thumpUp(String userId, String articleId) {
        Article article = articleDao.selectById(articleId);
        article.setThumbup(article.getThumbup() + 1);
        articleDao.updateById(article);

        //消息通知
        TbNotice notice = new TbNotice();
        notice.setReceiverid(article.getUserid());
        notice.setOperatorid(userId);
        notice.setAction("thumbup");
        notice.setTargettype("article");
        notice.setTargetid(articleId);
        notice.setCreatetime(new Date());
        notice.setType("user");
        notice.setState("0");

        noticeClient.save(notice);

        //创建Rabbit管理器
        RabbitAdmin rabbitAdmin = new RabbitAdmin(rabbitTemplate.getConnectionFactory());
        //创建队列，每个用户都有自己的队列，通过用户id进行区分
        Queue queue = new Queue("article_thumbup_" + article.getUserid(), false);
        rabbitAdmin.declareQueue(queue);
        //发送消息
        rabbitTemplate.convertAndSend("article_thumbup_" + article.getUserid(), articleId);
    }

}
